using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;

namespace Infrastructure.Security
{
    /// <summary>
    /// RSA加解密
    /// </summary>
    public static class RSA
    {
        /// <summary>
        /// 产生密钥对
        /// </summary>
        /// <returns>密钥字典，第一项为公钥，第二项为私钥</returns>
        public static Dictionary<string, string> CreateKey()
        {
            using (var rsa = System.Security.Cryptography.RSA.Create())
            {
                // 生成公钥
                string publicKey = rsa.ToXmlString(false);

                // 生成私钥
                string privateKey = rsa.ToXmlString(true);

                // 将公钥和私钥添加到返回结果
                Dictionary<string, string> keyDict = new Dictionary<string, string>();
                keyDict.Add("PublicKey", publicKey);
                keyDict.Add("PrivateKey", privateKey);

                return keyDict;
            }
        }

        /// <summary>
        /// 使用RSA算法对字符串进行加密
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="publicKey">公钥</param>
        /// <returns>密文</returns>
        public static string Encrypt(string plainText, string publicKey)
        {
            // 公钥为空
            if (string.IsNullOrEmpty(publicKey))
            {
                throw new ArgumentException("Invalid public key");
            }

            if (plainText == null)
            {
                plainText = string.Empty;
            }

            using (var rsa = System.Security.Cryptography.RSA.Create())
            {
                // 字符串转换为字节数组
                Byte[] toEncrypt = UTF8Encoding.UTF8.GetBytes(plainText);

                // 加载公钥
                rsa.FromXmlString(publicKey);

                // 单块最大长度
                int bufferSize = (rsa.KeySize / 8) - 11;
                Byte[] buffer = new byte[bufferSize];

                using (System.IO.MemoryStream inputStream = new System.IO.MemoryStream(toEncrypt),
                     outputStream = new System.IO.MemoryStream())
                {
                    while (true)
                    {
                        int readSize = inputStream.Read(buffer, 0, bufferSize);

                        if (readSize <= 0)
                        {
                            break;
                        }

                        // 分段加密
                        Byte[] temp = new byte[readSize];
                        Array.Copy(buffer, 0, temp, 0, readSize);
                        Byte[] encrypted = rsa.Encrypt(temp, RSAEncryptionPadding.Pkcs1);
                        outputStream.Write(encrypted, 0, encrypted.Length);
                    }

                    // 返回密文
                    return Convert.ToBase64String(outputStream.ToArray());
                }
            }
        }

        /// <summary>
        /// 使用RSA算法对字符串进行加密
        /// </summary>
        /// <param name="plainText">明文</param>
        /// <param name="publicKey">公钥</param>
        /// <returns>Url合法的密文</returns>
        public static string EncryptUrl(string plainText, string publicKey)
        {
            // 加密并进行Url编码
            string cipherText = Encrypt(plainText, publicKey);
            cipherText = Url.Encode(cipherText);

            return cipherText;
        }

        /// <summary>
        /// 使用RSA算法对字符串进行解密
        /// </summary>
        /// <param name="cipherText">密文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>明文</returns>
        public static string Decrypt(string cipherText, string privateKey)
        {
            // 私钥为空
            if (string.IsNullOrEmpty(privateKey))
            {
                throw new ArgumentException("Invalid private key");
            }

            if (cipherText == null)
            {
                cipherText = string.Empty;
            }

            using (var rsa = System.Security.Cryptography.RSA.Create())
            {
                // 字符串转换为字节数组
                Byte[] toDecrypt = Convert.FromBase64String(cipherText);

                // 加载私钥
                rsa.FromXmlString(privateKey);

                // 单块最大长度
                int bufferSize = rsa.KeySize / 8;
                Byte[] buffer = new byte[bufferSize];

                using (System.IO.MemoryStream inputStream = new System.IO.MemoryStream(toDecrypt),
                     outputStream = new System.IO.MemoryStream())
                {
                    while (true)
                    {
                        int readSize = inputStream.Read(buffer, 0, bufferSize);

                        if (readSize <= 0)
                        {
                            break;
                        }

                        // 分段解密
                        var temp = new byte[readSize];
                        Array.Copy(buffer, 0, temp, 0, readSize);
                        var rawBytes = rsa.Decrypt(temp, RSAEncryptionPadding.Pkcs1);
                        outputStream.Write(rawBytes, 0, rawBytes.Length);
                    }

                    // 返回明文 
                    return Encoding.UTF8.GetString(outputStream.ToArray());
                }

            }
        }

        /// <summary>
        /// 使用RSA算法对字符串进行解密
        /// </summary>
        /// <param name="cipherText">Url合法的密文</param>
        /// <param name="privateKey">私钥</param>
        /// <returns>明文</returns>
        public static string DecryptUrl(string cipherText, string privateKey)
        {
            if (cipherText == null)
            {
                cipherText = string.Empty;
            }

            // 还原密文
            cipherText = Url.Decode(cipherText);

            // 解密
            string plainText = Decrypt(cipherText, privateKey);

            return plainText;
        }


//#region 自定义 暂不管

//        /// <summary>
//        /// RSA加密
//        /// </summary>
//        /// <param name="content"></param>
//        /// <returns></returns>
//         static string RSAEncrypt(string content)
//        {
//            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
//            byte[] cipherbytes;
//            rsa.FromXmlString(RSAPublicKeyJava2DotNet(publickey));
//            //加密字符串太长可使用
//            // byte[] zz = Encoding.GetEncoding("gb2312").GetBytes(content);
//            //正常加密使用
//            byte[] bytes =Encoding.UTF8.GetBytes(content);
//            cipherbytes = rsa.Encrypt(bytes, false);

//            return Convert.ToBase64String(cipherbytes);
//        }
        
//        /// <summary>
//        /// 私钥加密
//        /// </summary>
//        /// <param name="value">加密数据</param>
//        /// <param name="privateKey">私钥</param>
//        /// <returns></returns>
//        static string RsaSign(string value, string privateKey)
//        {
//            //转换成适用于.Net的秘钥
//            var netKey = RSAPrivateKeyJava2DotNet(privateKey);
//            var rsa = new RSACryptoServiceProvider();
//            rsa.FromXmlString(netKey);
//            //创建一个空对象
//            var rsaClear = new RSACryptoServiceProvider();
//            var paras = rsa.ExportParameters(true);
//            rsaClear.ImportParameters(paras);
//            //签名返回
//            using (var sha256 = new SHA256CryptoServiceProvider())
//            {
//                var signData = rsa.SignData(Encoding.UTF8.GetBytes(value), sha256);
//                return Convert.ToBase64String(signData);
//            }
//        }


//        /// <summary>   
//        /// RSA公钥格式转换，java->.net   
//        /// </summary>   
//        /// <param name="publicKey">java生成的公钥</param>   
//        public static string RSAPublicKeyJava2DotNet(string publicKey)
//        {
//            RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
//            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
//                Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
//                Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
//        }
//        /// <summary>
//        /// RSA私钥格式转换，java->.net
//        /// </summary>
//        /// <param name="privateKey">java生成的RSA私钥</param>
//        /// <returns></returns>
//        static string RSAPrivateKeyJava2DotNet(string privateKey)
//        {
//            RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
//            return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
//                Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
//                Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
//        }
//        #endregion
    }
}
